﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AgileNETSlayer.Core;
using Mono.Cecil;
using Mono.Cecil.Cil;
using System.Reflection;

namespace AgileNETSlayer.Transforms
{
    class ProxyCall : ITransform
    {

        string file = @"C:\Users\JAdamita\Desktop\Secured\CrackMe_3";

        AssemblyDefinition assembly;
        int typeKey = 0;
        int methodKey = 0;
        string key = string.Empty;
        ModuleHandle moduleHandle;

        public ProxyCall(AssemblyDefinition assembly)
        {
            this.assembly = assembly;

            if (validate())
                process();
        }

        public bool validate()
        {
            return true;
        }

        public void process()
        {
            findConstants();
            Console.WriteLine("Proxy Class: " + findProxyInitClass().Name);
            Console.WriteLine("Type Key: " + typeKey);
            Console.WriteLine("Method Key: " + methodKey);
            Console.WriteLine();

            moduleHandle = Assembly.LoadFrom(file + ".exe").GetModules()[0].ModuleHandle;
            Console.WriteLine("Found ModuleHandle...");
            Console.WriteLine();

            Console.WriteLine("Searching for Proxy Calls...");
            foreach (TypeDefinition typeDef in assembly.MainModule.Types)
            {

                if (typeDef.Name.Equals("<module>"))
                    continue;

                foreach (MethodDefinition methodDef in typeDef.Methods)
                {
                    if (methodDef.IsConstructor)
                        continue;

                    if (methodDef.HasBody)
                    {
                        foreach (Instruction i in methodDef.Body.Instructions)
                        {
                            if (i.OpCode.Equals(OpCodes.Ldsfld) && !i.Operand.ToString().Contains("System.") && !i.Operand.ToString().Contains("Settings::"))
                            {
                                if (i.Operand.ToString().Contains("::"))
                                {
                                    Console.WriteLine("Call: " + i.Operand.ToString());
                                }
                            }
                        }
                    }
                }
            }

        }

        private void getMethod(int index)
        {
            Type typeFromHandle;
            typeFromHandle = Type.GetTypeFromHandle(moduleHandle.ResolveTypeHandle(typeKey + index));
            foreach (FieldInfo info in typeFromHandle.GetFields(BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Static))
            {
               MethodInfo methodFromHandle;
               Delegate delegate2;
               string name = info.Name;
               if (name.EndsWith("%"))
               {
                   name = name.TrimEnd(new char[] { '%' });
               }
               uint num = BitConverter.ToUInt32(Convert.FromBase64String(name), 0);
               try
               {
                   methodFromHandle = (MethodInfo)MethodBase.GetMethodFromHandle(moduleHandle.ResolveMethodHandle(((int)num) + methodKey));
               }
               catch
               {
                   continue;
               }
               if (methodFromHandle.IsStatic)
               {
                   try
                   {
                       delegate2 = Delegate.CreateDelegate(info.FieldType, methodFromHandle);
                       info.SetValue(null, delegate2);
                   }
                   catch (Exception)
                   {
                       continue;
                   }
               }
               Console.WriteLine("Method: " + methodFromHandle.ReflectedType.FullName + "." + methodFromHandle.Name);
            }
        }

        private void findConstants()
        {
            foreach (MethodDefinition methodDef in findProxyInitClass().Methods)
            {

                if (methodDef.IsConstructor)
                    continue;

                key = findProxyInitClass().Name;
                typeKey = int.Parse(methodDef.Body.Instructions[1].Operand.ToString());
                methodKey = int.Parse(methodDef.Body.Instructions[52].Operand.ToString());
            }
        }

        private TypeDefinition findProxyInitClass()
        {
            foreach (TypeDefinition typeDef in assembly.MainModule.Types)
            {

                if (typeDef.Fields.ToArray().Length != 2)
                    continue;

                if (!typeDef.Name.StartsWith("{"))
                    continue;

                foreach (FieldDefinition fieldDef in typeDef.Fields)
                {
                    if (fieldDef.FullName.Contains("ModuleHandle"))
                    {
                        return typeDef;
                    }
                }
            }
            return null;
        }

    }
}
